package com.caishi.lkx.exam.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.caishi.lkx.common.ienum.ClientType;
import com.caishi.lkx.common.util.IndexUtil;
import com.caishi.lkx.exam.mapper.ColumnMapper;
import com.caishi.lkx.exam.mapper.ExColumnConfigReMapper;
import com.caishi.lkx.exam.model.ChapterModel;
import com.caishi.lkx.exam.model.ColumnModel;
import com.caishi.lkx.exam.model.PaperModel;
import com.caishi.lkx.exam.service.ICategoryService;
import com.caishi.lkx.exam.service.IChapterService;
import com.caishi.lkx.exam.service.IColumnService;
import com.caishi.lkx.exam.service.IPaperService;
import com.zzw.common.Wrappers;
import com.zzw.common.entity.IBSEntity;
import com.zzw.common.entity.IBaseMapper;
import com.zzw.common.entity.impl.BaseEntity;
import com.zzw.common.exception.BizException;
import com.zzw.common.service.model.base.SortModel;

import com.caishi.lkx.exam.ienum.type.ColumnType;

import com.caishi.lkx.exam.model.re.ExColumnConfigReModel;

import com.caishi.lkx.order.IAssetsModel;
import com.caishi.lkx.order.ienum.type.AssetsType;
import com.caishi.lkx.order.model.OrderModel;
import com.caishi.lkx.order.service.IUserAssetsDataService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class ColumnServiceImpl implements IColumnService {
    private final String MORE_PAPER_NAME = "更多试卷";
    @Resource
    private ColumnMapper columnMapper;
    @Resource
    private ICategoryService categoryService;

    @Resource
    private ExColumnConfigReMapper exColumnConfigReMapper;

    @Resource
    private IUserAssetsDataService userAssetsDataService;

    @Resource
    private IChapterService chapterService;

    @Resource
    private IPaperService paperService;

    public static <T extends SortModel<T> & IBSEntity<T, String>,FreeModel > Comparator<T> reComparator(Map<String, ExColumnConfigReModel> reMap) {
        return (v, v1) -> {
//            var free1 = reMap.get(v.getId()).getIsFree();
//            var free2 = reMap.get(v1.getId()).getIsFree();
//            if (!free1.equals(free2)) {
//                return free1 ? -1 : 1;
//            }
            var s = reMap.get(v.getId()).getSort();
            var s1 = reMap.get(v1.getId()).getSort();
            if (!Objects.equals(s, s1)) return Integer.compare(s, s1);
            Integer sort = v.getSort();
            Integer sort1 = v1.getSort();
            return Integer.compare(null != sort1 ? sort1 : 0, null != sort ? sort : 0);
        };
    }

    @Override
    public IBaseMapper<ColumnModel, String> getMapper() {
        return columnMapper;
    }

    @Override
    public String queryNames(List<String> columnIds) {
        if (CollUtil.isNotEmpty(columnIds)) {
            return this.selectBatchIds(columnIds).stream().map(ColumnModel::getName).collect(Collectors.joining(","));
        }
        return null;
    }

    @Override
    public List<ColumnModel> queryCategoryColumns(Long categoryId) {
        return selectList(wrapperProcessing(wrappers().eq(ColumnModel::getCategoryId, categoryId)));
    }

    @Override
    public List<String> categoryColumn(Long categoryId, ColumnType columnType) {
        return selectList(wrappers()
                .select(ColumnModel::getId)
                .eq(ColumnModel::getCategoryId, categoryId)
                .eq(ColumnModel::getType, columnType)
        ).stream().map(BaseEntity::getId).toList();
    }

    @Override
    public void categoryUpdateColumn(Long categoryId, List<ColumnModel> data) {
        if (data == null) {
            return;
        }
        List<ColumnModel> oldData = queryCategoryColumns(categoryId);
        List<String> upIds = data.stream().map(ColumnModel::getId).filter(StrUtil::isNotBlank).toList();
        List<String> oldIds = oldData.stream().map(ColumnModel::getId).toList();
        List<String> delIds = oldIds.stream().filter(id -> !upIds.contains(id)).toList();
        for (ColumnModel da : data) {
            if (StrUtil.isBlank(da.getId())) {
                da.setCategoryId(categoryId);
                insert(da);
            } else {
                update(da);
            }
        }
        if (CollUtil.isNotEmpty(delIds)) {
            delete(delIds);
        }
    }


    @Override
    public IAssetsModel<ColumnModel, String> assetsDetail(String id) {
        ColumnModel columnModel = getById(id);
        if (ObjectUtil.isNotEmpty(columnModel.getCategoryId())) {
            columnModel.setCategoryName(categoryService.getById(columnModel.getCategoryId()).getName());
        }
        return columnModel;
    }

    @Override
    public String orderOnlinePayTitle(OrderModel orderModel, String id) {
        return "";
    }


    @Override
    public List<String> fetchQuestionIds(List<String> columnIds, ColumnType columnType) {
        var ids = columnRelationCollectionIds(columnIds);
        if (ids.isEmpty()) return new LinkedList<>();
        List<List<String>> split = new LinkedList<>();
        for (var i = 0; i < ids.size(); i += 1000) {
            split.add(ids.subList(i, Math.min(ids.size(), i + 1000)));
        }
        if (columnType == ColumnType.chapterPractice) {
            return split.parallelStream().flatMap(v -> chapterService.selectList(
                                    Wrappers.<ChapterModel>query().in("id", v).select("content->'$**.id' as question_ids", "id", "leaf", "path")
                            ).stream()
                            .flatMap(v1 -> {
                                if (v1.getLeaf()) return Stream.of(v1);
                                return chapterService.allChildren(v1, -1, Wrappers.<ChapterModel>query().eq("leaf", true).select("content->'$**.id' as question_ids")).stream();
                            })
                            .filter(ObjectUtil::isNotEmpty)
                            .filter(f -> CollectionUtil.isNotEmpty(f.getQuestionIds()))
                            .flatMap(e -> e.getQuestionIds().stream())
            ).toList();
        } else if (columnType == ColumnType.paperLibrary) {
            return split.parallelStream().flatMap(v ->
                    {
                        List<PaperModel> paperModels = paperService.selectList(Wrappers.<PaperModel>query().select("content->'$**.id' as question_ids").in("id", v));
                        return paperModels.stream().filter(ObjectUtil::isNotEmpty).map(PaperModel::getQuestionIds).filter(CollectionUtil::isNotEmpty)
                                ;
                    }
            ).flatMap(Collection::stream).toList();
        } else {
            return new LinkedList<>();
        }
    }

    public Integer fetchQuestionSize(List<String> columnIds, ColumnType columnType) {
        var ids = columnRelationCollectionIds(columnIds);
        if (ids.isEmpty()) return 0;
        if (columnType == ColumnType.chapterPractice) {
            return chapterService.selectList(chapterService.wrappers()
                    .select(ChapterModel::getQcount)
                    .in(BaseEntity::getId, ids)
            ).parallelStream().map(ChapterModel::getQcount).mapToInt(Integer::valueOf).sum();

        } else if (columnType == ColumnType.paperLibrary) {
            return paperService.selectList(paperService.wrappers()
                    .select(PaperModel::getQcount)
                    .in(BaseEntity::getId, ids)
            ).parallelStream().map(PaperModel::getQcount).mapToInt(Integer::valueOf).sum();

        }
        return 0;
    }

    @Override
    public List<String> columnRelationCollectionIds(String columnId) {
        return exColumnConfigReMapper.selectList(Wrappers.<ExColumnConfigReModel>lambdaQuery()
                        .select(ExColumnConfigReModel::getConfigId)
                        .eq(ExColumnConfigReModel::getColumnId, columnId))
                .stream().map(ExColumnConfigReModel::getConfigId).toList();
    }

    @Override
    public List<String> columnRelationCollectionIds(List<String> columnIds) {
        if (columnIds.isEmpty()) return Collections.emptyList();
        var ls = IndexUtil.splitList(columnIds);
        return ls.stream().flatMap(v -> exColumnConfigReMapper.selectList(Wrappers.<ExColumnConfigReModel>lambdaQuery()
                                .select(ExColumnConfigReModel::getConfigId)
                                .in(ExColumnConfigReModel::getColumnId, columnIds))
                        .stream().map(ExColumnConfigReModel::getConfigId))
                .toList();
    }


    @Override
    public boolean currentHaveAuth(Long userGroupId, Long localGroupId, String userId, Long categoryId, String columnId, ClientType clientType) throws BizException {
        //auth = auth || categoryService.currentHaveAuth(userGroupId, localGroupId, userId, categoryId, clientType);
        return userAssetsDataService.userHaveAsset(userId, AssetsType.column, columnId);
    }

    @Override
    public ColumnModel morePaperByCategory(Long categoryId) {
        ColumnModel columnModel = this.selectFirst(Wrappers.<ColumnModel>lambdaQuery()
                .eq(ColumnModel::getType, ColumnType.paperLibrary)
                .eq(ColumnModel::getCategoryId, categoryId)
                .like(ColumnModel::getName, MORE_PAPER_NAME)
        );
        if (null == columnModel) {
            columnModel = new ColumnModel();
            columnModel.setType(ColumnType.paperLibrary);
            columnModel.setShow(false);
            columnModel.setCategoryId(categoryId);
            columnModel.setName(MORE_PAPER_NAME);
            columnModel.setSort(100);
            return this.insert(columnModel);
        }
        return columnModel;

    }
}
